var smooth = 3; /* 平滑程度，数字越小山越高 */
var waterLevel = 30; /* 水面高度 */
var size = 256; /* 地图边长 */
var Tree = true; /* 自动生成树 */
var Sugarcane = true; /* 自动生成甘蔗 */

// 改进的噪声函数
class ImprovedNoise {
    private p: number[] = [];

    constructor() {
        this.p = [ 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10,
            23, 190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87,
            174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, 60, 211,
            133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208,
            89, 18, 169, 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124, 123, 5,
            202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223, 183, 170, 213, 119,
            248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232,
            178, 185, 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249,
            14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205,
            93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180 ];

        for ( var i = 0; i < 256; i ++ ) {
            this.p[ 256 + i ] = this.p[ i ];
        }
    }

    private fade(t: number) {
        return t * t * t * ( t * ( t * 6 - 15 ) + 10 );
    }

    private lerp(t: number, a: number, b: number) {
        return a + t * ( b - a );
    }

    private grad(hash: number, x: number, y: number, z: number) {
        var h = hash & 15;
        var u = h < 8 ? x : y, v = h < 4 ? y : h == 12 || h == 14 ? x : z;
        return ( ( h & 1 ) == 0 ? u : - u ) + ( ( h & 2 ) == 0 ? v : - v );
    }

    noise(x: number, y: number, z: number) {
        var floorX = Math.floor( x ), floorY = Math.floor( y ), floorZ = Math.floor( z );

        var X = floorX & 255, Y = floorY & 255, Z = floorZ & 255;

        x -= floorX;
        y -= floorY;
        z -= floorZ;

        var xMinus1 = x - 1, yMinus1 = y - 1, zMinus1 = z - 1;

        var u = this.fade( x ), v = this.fade( y ), w = this.fade( z );

        var A = this.p[ X ] + Y, AA = this.p[ A ] + Z, AB = this.p[ A + 1 ] + Z, B = this.p[ X + 1 ] + Y, BA = this.p[ B ] + Z, BB = this.p[ B + 1 ] + Z;

        return this.lerp( w, this.lerp( v, this.lerp( u, this.grad( this.p[ AA ], x, y, z ),
            this.grad( this.p[ BA ], xMinus1, y, z ) ),
        this.lerp( u, this.grad( this.p[ AB ], x, yMinus1, z ),
            this.grad( this.p[ BB ], xMinus1, yMinus1, z ) ) ),
        this.lerp( v, this.lerp( u, this.grad( this.p[ AA + 1 ], x, y, zMinus1 ),
            this.grad( this.p[ BA + 1 ], xMinus1, y, zMinus1 ) ),
        this.lerp( u, this.grad( this.p[ AB + 1 ], x, yMinus1, zMinus1 ),
            this.grad( this.p[ BB + 1 ], xMinus1, yMinus1, zMinus1 ) ) ) );
    }
}

/*
var ImprovedNoise = function () {
    var p = [151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10,
        23, 190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87,
        174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, 60, 211,
        133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208,
        89, 18, 169, 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124, 123, 5,
        202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223, 183, 170, 213, 119,
        248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232,
        178, 185, 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249,
        14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205,
        93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180];

    for (var i = 0; i < 256; i++) {
        p[256 + i] = p[i];
    }

    function fade(t: number) {
        return t * t * t * (t * (t * 6 - 15) + 10);
    }

    function lerp(t: number, a: number, b: number) {
        return a + t * (b - a);
    }

    function grad(hash: number, x: number, y: number, z: number) {
        var h = hash & 15;
        var u = h < 8 ? x : y, v = h < 4 ? y : h == 12 || h == 14 ? x : z;
        return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
    }

    return {
        noise: function (x: number, y: number, z: number) {
            var floorX = Math.floor(x), floorY = Math.floor(y), floorZ = Math.floor(z);

            var X = floorX & 255, Y = floorY & 255, Z = floorZ & 255;

            x -= floorX;
            y -= floorY;
            z -= floorZ;

            var xMinus1 = x - 1, yMinus1 = y - 1, zMinus1 = z - 1;

            var u = fade(x), v = fade(y), w = fade(z);

            var A = p[X] + Y, AA = p[A] + Z, AB = p[A + 1] + Z, B = p[X + 1] + Y, BA = p[B] + Z, BB = p[B + 1] + Z;

            return lerp(w, lerp(v, lerp(u, grad(p[AA], x, y, z),
                grad(p[BA], xMinus1, y, z)),
                lerp(u, grad(p[AB], x, yMinus1, z),
                    grad(p[BB], xMinus1, yMinus1, z))),
                lerp(v, lerp(u, grad(p[AA + 1], x, y, zMinus1),
                    grad(p[BA + 1], xMinus1, y, zMinus1)),
                    lerp(u, grad(p[AB + 1], x, yMinus1, zMinus1),
                        grad(p[BB + 1], xMinus1, yMinus1, zMinus1))));
        }
    };
};
*/
// 生成高度图
function generateHeight(width: number, height: number) {
    const size = width * height, data = new Uint8Array(size);
    const perlin = new ImprovedNoise();
    const z = Math.random() * 100;
    let quality = 1;
    const maxQuality = 100; // 限制 quality 的最大值

    for (let j = 0; j < 4; j++) {
        for (let i = 0; i < size; i++) {
            const x = i % width;
            const y = Math.floor(i / width);
            data[i] += Math.abs(perlin.noise(x / quality, y / quality, z) * quality * 1.75);
        }
        quality *= 5;
        if (quality > maxQuality) {
            quality = maxQuality; // 限制 quality 的最大值
        }
    }
    return data;
}

// 生成树
async function tree(x: number, y: number, z: number) {
    try {
        if (voxels.getVoxel(x, y, z) != voxels.id("water")) {
            var rand = 1;
            for (let i = y + rand; i < y + 4 + rand; i++) {
                voxels.setVoxel(x, i, z, "acacia");
            }
            for (let i = 3 + rand; i < 5 + rand; i++) {
                for (let j = -2; j < 3; j++) {
                    for (let k = -2; k < 3; k++) {
                        voxels.setVoxel(x + j, y + i, z + k, "green_leaf"); 
                    }
                }
            }
            for (let j = -1; j < 2; j++) {
                for (let k = -1; k < 2; k++) {
                    voxels.setVoxel(x + j, y + 5 + rand, z + k, "green_leaf"); 
                }
            }
            voxels.setVoxel(x - 1, y + 6 + rand, z, "green_leaf"); 
            voxels.setVoxel(x, y + 6 + rand, z, "green_leaf"); 
            voxels.setVoxel(x + 1, y + 6 + rand, z, "green_leaf"); 
            voxels.setVoxel(x, y + 6 + rand, z - 1, "green_leaf"); 
            voxels.setVoxel(x, y + 6 + rand, z + 1, "green_leaf"); 
            voxels.setVoxel(x, y + 4, z, "acacia");
            voxels.setVoxel(x, y + 5, z, "acacia");
        }
    } catch (error) {
        console.error("生成树时发生错误:", error);
    }
}

// 生成树
async function spawnTree() {
    try {
        for (let i = 0; i < size; i++) {
            for (let j = 0; j < size; j++) {
                for (let k = 0; k < 57; k++) {
                    if (voxels.getVoxel(i, k, j) == voxels.id("grass")) {
                        if (Math.random() * 150 <= 0.5) {
                            await tree(i, k, j);
                        }
                    }
                }
                await sleep(1); // 降低生成速度
            }
        }
    } catch (error) {
        console.error("生成树群时发生错误:", error);
    }
}

// 生成甘蔗
function bamboo(x: number, y: number, z: number) {
    try {
        if (voxels.getVoxel(x, y, z) != voxels.id("water")) {
            var rand = 1;
            for (let i = y + rand; i < y + 3 + rand; i++) {
                voxels.setVoxel(x, i, z, "bamboo");
            }
        }
    } catch (error) {
        console.error("生成甘蔗时发生错误:", error);
    }
}

// 生成甘蔗群
async function spawnSugarcane() {
    try {
        for (let i = 0; i < size; i++) {
            for (let j = 0; j < size; j++) {
                for (let k = 0; k < 57; k++) {
                    if (voxels.getVoxel(i, k, j) == voxels.id("sand")) {
                        if (Math.random() * 150 <= 4) {
                            await bamboo(i, k, j);
                        }
                    }
                }
                await sleep(1); // 降低生成速度
            }
        }
    } catch (error) {
        console.error("生成甘蔗群时发生错误:", error);
    }
}

(async function () {
    console.log("start");
    var heightData = generateHeight(size, size);

    for (let i = 0; i < heightData.length; i += size) {
        for (let j = i; j < Math.min(i + size, heightData.length); j++) { // 确保不越界
            var x = Math.floor(i / size);
            var y = Math.round(heightData[j] / smooth + 2) + 20;
            var z = j - i;

            if (y > waterLevel) voxels.setVoxel(x, y, z, "grass");
            else if (y == waterLevel) voxels.setVoxel(x, y, z, "sand");
            else {
                voxels.setVoxel(x, y, z, "dirt");
                for (let s = y + 1; s <= waterLevel; s++) voxels.setVoxel(x, s, z, "water");
            }

            for (let s = 3; s < y - 3; s++) voxels.setVoxel(x, s, z, "stone");
            for (let s = 0; s < 3; s++) voxels.setVoxel(x, s, z, "dark_brick_02");
            for (let s = y - 3; s < y; s++) voxels.setVoxel(x, s, z, "dirt");

            if (Math.random() < 0.01) await sleep(1); // 降低生成速度
        }
    }

    if (Tree) {
        await spawnTree();
    }
    if (Sugarcane) {
        await spawnSugarcane();
    }
    console.log("生成完毕");
})();